package readini

import (
	"bufio"
	"io"
	"os"
	"runtime"
	"strings"
)

var commentsign byte

//Section 封装map[string]string
type Section map[string]string

//Configuration 封装map[string]map[string]string
type Configuration map[string]Section

//NoSuchSectionException 段不存在异常
type NoSuchSectionException string

//NoSuchKeyException 键不存在异常
type NoSuchKeyException string

//NoSuchFileException 没有该文件异常
type NoSuchFileException string

//ReadlineException 是读取文件异常
type ReadlineException string

//Listener 接口
type Listener interface {
	listen(ini string)
}

//MyListener 是喜爱年了Listener接口
type MyListener struct {
	channel chan int
}

func (m MyListener) listen(ini string) {
	time, err := os.Stat(ini)
	if err != nil {
		panic(err)
	}
	go func() {
		for {
			newtime, _ := os.Stat(ini)
			if time.ModTime() != newtime.ModTime() {
				m.channel <- 1
				break
			}
		}
	}()
}

func (e NoSuchSectionException) Error() string {
	return "No such Section"
}

func (e NoSuchKeyException) Error() string {
	return "No such Key"
}
func (e NoSuchFileException) Error() string {
	return "No such File"
}
func (e ReadlineException) Error() string {
	return "Cant Read"
}
func (c Configuration) getSection(key string) (Section, error) {
	value, err := c[key]
	if err == false {
		return nil, NoSuchSectionException("")
	}
	return value, nil

}

func (c Configuration) newSection(key string) {
	c[key] = make(Section)
}

func (s Section) getVal(key string) (string, error) {
	value, err := s[key]
	if err == false {
		return "", NoSuchKeyException("")
	}
	return value, nil
}

func (s Section) newVal(key, val string) {
	s[key] = val
}

func init() {
	if runtime.GOOS == "windows" {
		commentsign = ';'
	} else {
		commentsign = '#'
	}
}

//ReadFileToConfig is to read file to Configuration struct
func ReadFileToConfig(filename string) (Configuration, error) {

	c := make(Configuration)
	f, err := os.Open(filename)
	if err != nil {
		return nil, NoSuchFileException("")
	}
	readerr := bufio.NewReader(f)
	secname := "DEFAULT"
	c.newSection(secname)
	for {
		str, err := readerr.ReadString('\n')
		if err == io.EOF {
			return c, nil
		}
		if err != nil {
			return nil, ReadlineException("")
		}
		str = strings.TrimSpace(str)
		if str == "" || str[0] == commentsign {
			continue
		}

		if str[0] == '[' && str[len(str)-1] == ']' {

			secname = str[1 : len(str)-1]
			c.newSection(secname)
		} else {
			pair := strings.Split(str, "=")
			key, value := pair[0], pair[1]
			key = strings.TrimSpace(key)
			value = strings.TrimSpace(value)
			sec, _ := c.getSection(secname)
			sec.newVal(key, value)
		}
	}
}

//WatchWithOption 可以显式指定注释符号
func WatchWithOption(filename string, listener Listener, com byte) (Configuration, error) {
	commentsignCopy := commentsign
	commentsign = com
	conf, err := Watch(filename, listener)
	commentsign = commentsignCopy
	return conf, err
}

//Watch 接受文件名和Listener，等到文件被修改就返回这个配置文件
func Watch(filename string, lis Listener) (Configuration, error) {

	lis.listen(filename)

	liss, _ := lis.(MyListener)

	if <-liss.channel == 1 {
		return ReadFileToConfig(filename)
	}
	return nil, nil
}
